/******************** (C) COPYRIGHT 2018 merafour ********************
* Author             : 冷月追风@merafour.blog.163.com
* Version            : V1.0.0
* Date               : 8/1/2019
* Description        : 串口操作.
********************************************************************************
* merafour.blog.163.com
* merafour@163.com
* github.com/Merafour
*******************************************************************************/
#ifndef QISERIALPORT_H
#define QISERIALPORT_H

#include <QObject>
#include <QSerialPort>
#include <QSerialPortInfo>
#include <QListView>
#include <QStandardItemModel>
#include <QString>
#include <QStringList>
#include <QTimer>
#include <QThread>

#include "qimsgport.h"
#include "qiqueue.h"

class QiSerialPort : public QiMSGPort
{
    Q_OBJECT
public:
    explicit QiSerialPort(QObject *parent = nullptr);
    ~QiSerialPort()
    {
        disconnect(&_Port, &QSerialPort::errorOccurred, this, &QiSerialPort::errorOccurred_slots);
        //disconnect(&_Port, SIGNAL(errorOccurred()), this, SLOT(errorOccurred_slots()));
        close();
    }

    void flush_serial(void);
    static QStringList GetPortNames(void);
    static QString search_Description(const QString desc);
    virtual int OpenPortDefault(const QString &name);
    virtual void close(void)
    {
        //disconnect(&_Port, &QSerialPort::readyRead, this, &QiSerialPort::recSerialData);
        //disconnect(&_Port, SIGNAL(readyRead()), this, SLOT(recSerialData()));
        _Port.close();
    }
    virtual uint8_t stop(void) { return _stop; }
    virtual void clear(void)
    {
        _Port.clear();
        queue->reset();
    }
    virtual void flush(void)
    {
        _Port.flush();
    }
    virtual qint64 write(const char *data, qint64 len)
    {
        if(1==_stop) return 0;
        return _Port.write(data, len);
    }
    virtual int read(uint8_t buf[], const int count = 2)
    {
        int len=0;
        //if(_Port.waitForReadyRead(1)) recSerialData();
        watting_data(100);
        for(len=0; len<count; len++)
        {
            if(queue->size())
            {
                buf[len] = static_cast<uint8_t>(queue->get());
                continue;
            }
            watting_data(100);  // watting 10ms
            buf[len] = static_cast<uint8_t>(queue->get());
        }
        return 0;
    }
    virtual uint8_t read(void)
    {
        if(_Port.waitForReadyRead(1)) recSerialData();
        if(!queue->is_empty()) return static_cast<uint8_t>(queue->get());
        watting_data(10);  // watting 10ms
        return static_cast<uint8_t>(queue->get());
    }
    int watting_data(const uint32_t timeout)
    {
        if(queue->size()) return static_cast<int>(queue->size());
        uint32_t _time;
        for(_time=0; _time<timeout; _time++)
        {
            _Port.waitForReadyRead(1);
            recSerialData();
            //if(!queue->is_empty()) break;
            if(queue->size()) break;
            if(0!=stop()) break;
        }
        return static_cast<int>(queue->size());
    }

signals:

public slots:
    void errorOccurred_slots(QSerialPort::SerialPortError error);
    void recSerialData(void)
    {
        QByteArray ba;
        ba = _Port.readAll();
    #if 0
        int count=0;
        const char* datas = ba.constData();
        int len = ba.size();
        for(count=0; count<len; count++)
        {
            queue->put(static_cast<uint8_t>(datas[count]));
            //qDebug("%02X ", datas[count]);
        }
    #else
        queue->put_array(ba.constData(), ba.size());
    #endif
    }
private:
    uint8_t _stop;
    QSerialPort _Port;
    QiQueue *queue;
};

#endif // QISERIALPORT_H
